local CopyL = require("copy.CopyL")
local CopyDefine = require("copy.Define")
local InnerDataManagerFL = require("innerdata.InnerDataManagerFL")
local InnerDataDefine = require("innerdata.Define")
local Obj = require("core.Obj")
local ExcelMapConf = require("excel.Map")
local Map = require("core.Map")
local ObjMonster = require("core.ObjMonster")
local Util = require("common.Util")
local Msg = require("core.Msg")
local DailyActFL = require("activity.DailyActFL")
local ActDefine = require("activity.Define")
local Broadcast = require("broadcast.Broadcast")
local Lang = require("common.Lang")
local OfficialLogic = require("official.OfficialLogic")

WorldBossData = WorldBossData or {}
HurtList = HurtList or nil 
HurtRankList = HurtRankList or nil 
HeartBeatCount = HeartBeatCount or {}

function onCreateBoss(nData)
    if DailyActFL.onCheckActIsRunning(ActDefine.ACT_TYPE_WORLDBOSS) then
        return
    end

    local nMonsterID = nData.data.monsterID
    local nMapID = nData.data.mapID
    local nCopyID = nData.data.copyID

    local nTempData = {}
    Util.copyTable(nData.data, nTempData)
    WorldBossData = {_configData = nTempData, boss = nil, monsterList = {}, curLastHitName = nil, curLastHitUuid = nil}

    local logicID = Map.get_logic_id(nMapID)
    if _G.logic_id == logicID then
        WorldBossData.boss = ObjMonster.create(nMonsterID)
        WorldBossData.killFlag = nil
        HurtList = (HurtList and HurtList[nCopyID]) and HurtList[nCopyID] or {[nCopyID] = {}} 
        HurtRankList = (HurtRankList and HurtRankList[nCopyID]) and HurtRankList[nCopyID] or {[nCopyID] = {}}
    end
end

function onWorldBossMonsterBeHit(attacker, monster, monsterID, hurt, copyID, roomID, sceneID)
    if not WorldBossData or WorldBossData.killFlag == true then 
        return 
    end

    local getHp = Obj.getHp
    local currHp = getHp(WorldBossData.boss)
    local hp = currHp - hurt 
    Obj.setHp(WorldBossData.boss, hp)
    --如果没有死亡，将1秒同步一次
    if hp < 1 then
        onEnd(attacker)
        WorldBossData.killFlag = true
        for nRoomID, v in pairs(WorldBossData.monsterList) do
            Obj.setHp(v, hp)
            if hp < 1 then
                if v.id ~= monster.id then
                    Obj.onDie(v, attacker, nil, nil, nil, true)
                end
            end
        end
    end

    local humanName = attacker.name
    if not sceneID or sceneID <= 0 or not HurtList or not HurtList[copyID] then
        return
    end

    local nHurtData = HurtList[copyID]
    if not nHurtData[humanName] then
      OfficialLogic.checkOneCondition(attacker, "worldBoss")
    end
    nHurtData[humanName] = (nHurtData[humanName] or 0) + hurt

    local nHurtStats = nHurtData[humanName]

    local nBeforeRank = 0
    local nCurRank = 0
    local nHurtRankData = HurtRankList[copyID]
    if not nHurtRankData then
        return
    end
    if #nHurtRankData < 20 or nHurtStats > nHurtRankData[20][2] then
        if #nHurtRankData == 0 then
            onAddRankList(nHurtRankData, 1, attacker, nHurtStats)
        else
            for k,v in ipairs(nHurtRankData) do
                if v[1] == humanName then
                    nBeforeRank = k
                    break
                end
            end

            if nBeforeRank == 1 then
                nHurtRankData[1][2] = nHurtStats 
                nCurRank = 1
            else
                if nBeforeRank > 0 and nHurtStats <= nHurtRankData[nBeforeRank - 1][2] then
                    nHurtRankData[nBeforeRank][2] = nHurtStats 
                    nCurRank = nBeforeRank 
                else --增加积分后排名发生变化
                    local nBegin = 0
                    if nBeforeRank > 0 then --之前已有排名则先删除
                        table.remove(nHurtRankData, nBeforeRank)
                        nBegin = nBeforeRank - 1
                    else
                        if #nHurtRankData > 20 then
                            nBegin = 20
                        else
                            nBegin = #nHurtRankData 
                        end
                    end
                    if nHurtStats <= nHurtRankData[nBegin][2] then
                        onAddRankList(nHurtRankData, nBegin + 1, attacker, nHurtStats)
                        nCurRank = nBegin + 1
                    else
                        for k = nBegin, 1, -1 do
                            if k == 1 then
                                if nHurtStats < nHurtRankData[k][2] then 
                                    onAddRankList(nHurtRankData, k + 1, attacker, nHurtStats)
                                    nCurRank = k + 1
                                    break
                                else
                                    onAddRankList(nHurtRankData, 1, attacker, nHurtStats)
                                    nCurRank = 1
                                    break
                                end
                            else
                                if nHurtStats <= nHurtRankData[k][2] then 
                                    onAddRankList(nHurtRankData, k + 1, attacker, nHurtStats)
                                    nCurRank = k + 1
                                    break
                                end
                            end
                        end
                    end
                end
            end
        end
    end
end

function onEnd(human)
    local nActData = DailyActFL.onGetActData(ActDefine.ACT_TYPE_WORLDBOSS)
    if nActData then
        if human then
            WorldBossData.curLastHitName = human.name
            WorldBossData.curLastHitUuid = human._id
        end
        local nHurtRankData = HurtRankList[CopyDefine.COPY_WORLDBOSS]
        local nSend2Wdata = {
            type = 1,
            data = {rankData = nHurtRankData, lastHit = human and {human.name, human._id} or nil, actArgs = nActData.actArgs, result = human and 0 or 1}
        }
        InnerDataManagerFL.Send2WInnerData(human, InnerDataDefine.INNERDATA_TYPE_WORLDBOSS, nSend2Wdata)
    end
end

function onGetBossLastHitData()
    if WorldBossData then
        return WorldBossData.curLastHitUuid
    end
end

function onGetBossData()
    if WorldBossData and WorldBossData.boss then
        return WorldBossData.boss
    end
end

function onCtlBossData()
    if not WorldBossData then
        return
    end

    if WorldBossData.boss then
        local getHp = Obj.getHp
        local currHp = getHp(WorldBossData.boss)
        local nMsg = Msg.gc.GC_OBJ_HP
        for nRoomID, v in pairs(WorldBossData.monsterList) do
            local hp_max = ObjMonster.getHpMax(v)
            Obj.setHp(v, currHp)
            nMsg.obj_id = v.id
            nMsg.hp = v.hp
            nMsg.hp_max = hp_max
            nMsg.mp = 0
            nMsg.mp_max = 0
            Obj.sendArea(nMsg, v.scene_id, v.x, v.y)
        end
    end

    HeartBeatCount[CopyDefine.COPY_WORLDBOSS] = (HeartBeatCount[CopyDefine.COPY_WORLDBOSS] or 0) + 1 
    if HeartBeatCount[CopyDefine.COPY_WORLDBOSS] % 5 == 0 then
        if not HurtList or not HurtList[CopyDefine.COPY_WORLDBOSS] or not HurtRankList or not HurtRankList[CopyDefine.COPY_WORLDBOSS] then
            return
        end

        local nMsg = Msg.gc.GC_WORLDBOSS_SCENEDATA
        nMsg.ranklist[0] = 0
        for k, v in ipairs(HurtRankList[CopyDefine.COPY_WORLDBOSS]) do
            nMsg.ranklist[0] = nMsg.ranklist[0] + 1
            local nRankData = nMsg.ranklist[nMsg.ranklist[0]]
            if nRankData then
                nRankData.name = v[1] 
                nRankData.hurt = v[2] 
            end
            if k >= 10 then
                break
            end
        end
        nMsg.lasttime = WorldBossData._configData.lasttime or 0
        nMsg.lefttime = WorldBossData._configData.endtime and (WorldBossData._configData.endtime - os.time()) or 0

        nMsg.myhurt = 0

        for roomID in pairs(WorldBossData.monsterList) do
            for _, nSceneID in pairs(CopyL.copyList[CopyDefine.COPY_WORLDBOSS][roomID]) do
                local nFds = Obj.scenes_fds[nSceneID]
                if nFds then
                    for k, v in pairs(nFds) do
                        if v.obj_type == Obj.TYPE_HUMAN then
                            nMsg.myhurt = HurtList[CopyDefine.COPY_WORLDBOSS][v.name] or 0
                            Msg.send(nMsg, k)
                        end
                    end
                end
            end
        end
    end
end

function onAddRankList(hurtRankData, oRank, human, oHurtStats)
    table.insert(hurtRankData, oRank, {human.name, oHurtStats, human._id})
end

function onClose()
    --local nMapID = WorldBossData.mapID 
    --if not nMapID then
    --    return
    --end
    --local logicID = Map.get_logic_id(nMapID)
    --if _G.logic_id == logicID then
    --    local nSceneID = Map.map_id_to_scene_id[nMapID][1]
    --    if nSceneID then
    --        SceneEvent.do_ai_by_callback(nSceneID, "ref")
    --        SceneEvent.sceneClear(nSceneID)
    --        HurtRankList[nSceneID] = nil 
    --        HurtList[nSceneID] = nil
    --    end
    --end
end

function checkEnter(human)
    local nStartTime, nEndTime = getActTime()
    if nStartTime <= 0 or nEndTime <= 0 then
        Broadcast.sendBroadcast(human, Lang.DOWN, Lang.JZWAR_NOT_START)  --活动暂未开启
        return false
    end
    if WorldBossData.killFlag == true then
        Broadcast.sendBroadcast(human, Lang.DOWN, "世界BOSS已被击杀")  --世界BOSS已被击杀
        return false
    end

    return true
end

--得到开始时间
function getActTime()
    local nActData = DailyActFL.onGetActData(ActDefine.ACT_TYPE_WORLDBOSS)
    if not nActData or nActData.status ~= ActDefine.ACT_STATE_RUNNING then
        return 0, 0
    end
    return nActData.startTime, nActData.endTime
end

function onWorldBossRoomBegin(copyID, roomID)
    local nMonsterPosX = WorldBossData._configData.posX 
    local nMonsterPosY = WorldBossData._configData.posY 
    local nMonsterID = WorldBossData._configData.monsterID
    if not WorldBossData.monsterList[roomID] then
        WorldBossData.monsterList[roomID] = ObjMonster.create(nMonsterID)
    end
    for _, nSceneID in pairs(CopyL.copyList[copyID][roomID]) do
        ObjMonster.enterScene(WorldBossData.monsterList[roomID], nSceneID, nMonsterPosX, nMonsterPosY)
    end
end

function onWorldBossRoomEnd()
    if WorldBossData.monsterList then
        for nRoomID in pairs(WorldBossData.monsterList) do
            CopyL.roomFinish(CopyDefine.COPY_WORLDBOSS, nRoomID, CopyDefine.COPY_FINISH_ACT_END, "活动结束")
        end
    end
    
    --如未被击杀
    local logicID = Map.get_logic_id(WorldBossData._configData.mapID)
    if _G.logic_id == logicID then
        if WorldBossData.killFlag ~= true then
            onEnd()
        end
    end

    if WorldBossData and WorldBossData.boss then
        Obj.destroy(WorldBossData.boss)
    end

    WorldBossData = nil
    HurtList = nil
    HurtRankList = nil
end

DailyActFL.onRegisterCallBack(ActDefine.ACT_TYPE_WORLDBOSS, nil, nil, onWorldBossRoomEnd)
